package com.kws.payment.business;

import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import com.kws.common.core.utils.StringUtils;
import com.kws.payment.dao.CreateWeixinPayNotifyRq;
import com.kws.payment.dao.CreateWeixinPayOrderRq;
import com.kws.payment.dao.RefundWeixinPayRq;
import com.kws.payment.dao.WeixinPayRefundRq;
import com.wechat.pay.contrib.apache.httpclient.util.AesUtil;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.service.payments.h5.H5Service;
import com.wechat.pay.java.service.payments.nativepay.NativePayService;
import com.wechat.pay.java.service.payments.nativepay.model.Amount;
import com.wechat.pay.java.service.payments.nativepay.model.CloseOrderRequest;
import com.wechat.pay.java.service.payments.nativepay.model.PrepayRequest;
import com.wechat.pay.java.service.payments.nativepay.model.PrepayResponse;
import com.wechat.pay.java.service.refund.RefundService;
import com.wechat.pay.java.service.refund.model.AmountReq;
import com.wechat.pay.java.service.refund.model.CreateRequest;
import com.wechat.pay.java.service.refund.model.Refund;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;

/**
 * <b>WeixinWebPayBusiness</b>
 *
 * @description: WeixinWebPayBusiness <br>
 * @date: 2024/11/13 09:31 <br>
 * @author: lhm <br>
 * @version: 1.0 <br>
 */

@Component
public class WeixinWebPayBusiness {
    private static final Logger logger = LoggerFactory.getLogger(WeixinWebPayBusiness.class);

    /** 商户号 */
    @Value("${weixinPay.merchantId}")
    public static String merchantId;
    /** 商户API私钥路径 */
    @Value("${weixinPay.privateKey_path}")
    public static String privateKeyPath;
    /** 商户证书序列号 */
    @Value("${weixinPay.merchant_serial_number}")
    public static String merchantSerialNumber;
    /** 商户APIV3密钥 */
    @Value("${weixinPay.api_key}")
    public static String apiV3key;

    /**
     * 应用appID
     */
    @Value("${weixinPay.app_id}")
    private static String appId;

    /**
     * 商户直连号
     */
    @Value("${weixinPay.mchid}")
    private static String mchid;

    /**
     * 支付回调通知地址
     */
    @Value("${weixinPay.notify_url}")
    private static String notifyUrl;


    /**
     * 微信支付web端支付预下单
     * @return
     */
    public String createWeixinWebPayOrder(CreateWeixinPayOrderRq rq){
        Config config =
                new RSAAutoCertificateConfig.Builder()
                        .merchantId(merchantId)
                        .privateKeyFromPath(privateKeyPath)
                        .merchantSerialNumber(merchantSerialNumber)
                        .apiV3Key(apiV3key)
                        .build();
        // 构建service
        NativePayService service = new NativePayService.Builder().config(config).build();
        PrepayRequest request = new PrepayRequest();
        Amount amount = new Amount();
        amount.setTotal(rq.getAmount());
        request.setAmount(amount);
        request.setAppid(appId);
        request.setMchid(mchid);
        request.setDescription(rq.getDescription());
        request.setNotifyUrl(notifyUrl);
        request.setOutTradeNo(rq.getOrderNo());
        // 调用下单方法，得到应答
        PrepayResponse response = service.prepay(request);
        logger.info("获取微信支付预下单返回支付地址："+response.getCodeUrl());
        return response.getCodeUrl();
    }

    /**
     * 微信web端支付关闭订单
     */
    public void closeWeixinWebPayOrder(String orderNo){
        Config config =
                new RSAAutoCertificateConfig.Builder()
                        .merchantId(merchantId)
                        .privateKeyFromPath(privateKeyPath)
                        .merchantSerialNumber(merchantSerialNumber)
                        .apiV3Key(apiV3key)
                        .build();
        NativePayService service = new NativePayService.Builder().config(config).build();
        CloseOrderRequest request = new CloseOrderRequest();
        //订单号
        request.setOutTradeNo(orderNo);
        request.setMchid(mchid);
        service.closeOrder(request);
    }

    /**
     * 微信支付退款申请
     */
    public Refund weixinPayRefund(WeixinPayRefundRq rq){
        Config config =
                new RSAAutoCertificateConfig.Builder()
                        .merchantId(merchantId)
                        .privateKeyFromPath(privateKeyPath)
                        .merchantSerialNumber(merchantSerialNumber)
                        .apiV3Key(apiV3key)
                        .build();
        RefundService service = new RefundService.Builder().config(config).build();
        CreateRequest request = new CreateRequest();
        AmountReq refundAmount = new AmountReq();
        //退单金额 单位分
        refundAmount.setRefund(rq.getRefundAmount());
        //原交易金额 单位分
        refundAmount.setTotal(rq.getOrderAmount());
        //退款币种
        refundAmount.setCurrency("CNY");
        request.setAmount(refundAmount);
        //订单号
        request.setOutTradeNo(rq.getOrderNo());
        //退单号
        request.setOutRefundNo(rq.getRefundOrderNo());
        if (StringUtils.isNotEmpty(rq.getRefundReason())) {
            //退款原因
            request.setReason(rq.getRefundReason());
        }
        //退款结果回调通知url
        request.setNotifyUrl(notifyUrl);
        Refund refund = service.create(request);
        logger.info("微信支付退款结果返回:{}"+ JSONUtil.parse(refund));
        return refund;
    }

    public CreateWeixinPayNotifyRq weixinNotify(JSONObject jsonObject) throws GeneralSecurityException {
        JSONObject resource = jsonObject.getJSONObject("resource");
        String ciphertext = resource.getString("ciphertext");
        String nonce = resource.getString("nonce");
        String associatedData = resource.getString("associated_data");
        AesUtil aesUtil = new AesUtil(apiV3key.getBytes(StandardCharsets.UTF_8));
        //密文解密
        String plainText = aesUtil.decryptToString(associatedData.getBytes(StandardCharsets.UTF_8),
                nonce.getBytes(StandardCharsets.UTF_8),
                ciphertext);
        CreateWeixinPayNotifyRq rq = JSONUtil.toBean(JSONUtil.parseObj(plainText), CreateWeixinPayNotifyRq.class);
        return rq;
    }

    public RefundWeixinPayRq refundOrder(JSONObject jsonObject) throws GeneralSecurityException {
        JSONObject resource = jsonObject.getJSONObject("resource");
        String ciphertext = resource.getString("ciphertext");
        String nonce = resource.getString("nonce");
        String associatedData = resource.getString("associated_data");
        AesUtil aesUtil = new AesUtil(apiV3key.getBytes(StandardCharsets.UTF_8));
        //密文解密
        String plainText = aesUtil.decryptToString(associatedData.getBytes(StandardCharsets.UTF_8),
                nonce.getBytes(StandardCharsets.UTF_8),
                ciphertext);
        RefundWeixinPayRq rq = JSONUtil.toBean(JSONUtil.parseObj(plainText), RefundWeixinPayRq.class);
        return rq;
    }
}
